package com.gitee.huxing.course.merchant.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gitee.huxing.course.merchant.domain.dao.PlatFormOrderMapper;
import com.gitee.huxing.course.merchant.domain.module.PlatFormOrderDO;
import com.gitee.huxing.course.merchant.service.PlatFormOrderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

/**
 * @Description:
 * @ProjectName: JavaCourse
 * @Package: com.gitee.huxing.course.service.impl
 * @ClassName: PlatFormOrderServiceImpl
 * @Author: huxing
 * @DateTime: 2021-09-17 下午5:37
 */
@Slf4j
@Service
public class PlatFormOrderServiceImpl extends ServiceImpl<PlatFormOrderMapper, PlatFormOrderDO>
        implements PlatFormOrderService {

    /** 线程总数  **/
    private static final int size = 1000;

    /** 记录条数 **/
    private static final int count = 1000;

    private ConcurrentHashMap<Integer, Object> recordMap = new ConcurrentHashMap<>();

    /** 统计线程执行时间 **/
    private CopyOnWriteArrayList<Integer> times = new CopyOnWriteArrayList<>();

    @Override
    public PlatFormOrderDO purchase() throws RuntimeException {
        // 提交订单
        PlatFormOrderDO orderDO = PlatFormOrderDO.createBuilderTest();
        // 提交订单记录
        this.baseMapper.insert(orderDO);
        // 返回订单记录
        return orderDO;
    }

    @Override
    public PlatFormOrderDO updateOrder(String orderId) throws RuntimeException {
        // 修改订单记录
        PlatFormOrderDO orderDO = PlatFormOrderDO.paymentOrderTest(orderId);
        this.baseMapper.update(orderDO);
        // 查询并返回修改后的订单记录
        return this.baseMapper.selectInfoById(orderId);
    }

    @Override
    public void deleteOrder(String orderId) throws RuntimeException {
        // 根据订单号删除订单记录
        this.baseMapper.delete(orderId);
    }

    @Override
    public void batchPurchase() throws RuntimeException {
        log.info("批量插入交易订单记录: {}", DateUtil.now());
        LocalDateTime startTime = LocalDateTime.now();
        ExecutorService service = Executors.newFixedThreadPool(10);
        CountDownLatch latch = new CountDownLatch(size);
        // 配置线程池
        log.info("线程池启动: {}", LocalDateTime.now());
        for (int i=0; i < size; i++){
            List<PlatFormOrderDO> list = new ArrayList<>(count);
            for (int j = 0; j < count; j++) {
                list.add(PlatFormOrderDO.createBuilderTest());
            }
            service.execute(new BatchPurchaseThread(this.baseMapper,
                    list, latch, times));
        }
        try {
            latch.await();
            log.info("总计操作耗时: {}s", LocalDateTimeUtil.between(startTime,
                    LocalDateTime.now()).getSeconds());
            log.info("线程最大耗时: {}", times.stream().mapToInt(Integer::intValue).max());
            log.info("线程最小耗时: {}", times.stream().mapToInt(Integer::intValue).min());
            log.info("线程平均耗时: {}", times.stream().mapToInt(Integer::intValue).average());
        } catch (Exception ex){
            ex.printStackTrace();
        }
        log.info("批量插入执行完成");
    }

    @Override
    public PlatFormOrderDO queryOrder(String orderId) throws RuntimeException {
        // TODO: 查询订单记录
        return this.baseMapper.selectInfoById(orderId);
    }

    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public void batchPurchaseTrans(Integer page){
        log.info("批量插入交易订单记录: {}", DateUtil.now());
        LocalDateTime startTime = LocalDateTime.now();
        log.info("开始创建记录对象: {}", startTime);
        List<PlatFormOrderDO> list = new ArrayList<>(1000);
        for (int i = 0; i < 16; i++) {
            list.add(PlatFormOrderDO.createBuilderTest());
        }
        log.info("记录对象创建成功，耗时: {}s", LocalDateTimeUtil.between(startTime,
                LocalDateTime.now()).getSeconds());
        this.baseMapper.batchInsert(list);
        // TODO: 简单测试
        log.info("生成的记录总计页码数: {}", list.size() / page);
        log.info("批量插入执行完成");
    }

    @SuppressWarnings("all")
    static class BatchPurchaseThread implements Runnable{
        /** 处理mapper **/
        private PlatFormOrderMapper mapper;
        /** 业务记录数 **/
        private List<PlatFormOrderDO> list;
        /** 同步处理锁 **/
        private CountDownLatch latch;
        /** 操作耗时 **/
        private CopyOnWriteArrayList times = new CopyOnWriteArrayList<>();

        public BatchPurchaseThread(PlatFormOrderMapper mapper, List list, CountDownLatch latch,
                                   CopyOnWriteArrayList times){
            this.mapper = mapper;
            this.list = list;
            this.latch = latch;
            this.times = times;
        }

        @Override
        public void run() {
            try {
                log.info("批量插入事务处理开始: {}", Thread.currentThread().getName());
                // 启动处理时间
                long startTime = System.currentTimeMillis();
                // 批量提交记录
                this.mapper.batchInsert(list);
                // 结束时间
                long endTime = System.currentTimeMillis();
                // 保存结束时间
                times.add((int) (endTime - startTime));
                // 批处理事务管理
                log.info("记录批处理提交完成: {}", Thread.currentThread().getName());
                // 当前线程结束关闭
                latch.countDown();
            } catch (Exception ex){
                ex.printStackTrace();
            }
        }
    }
}
